/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package antcolony;

import java.util.*;
import DeMaSoft.*;

/**
 *
 * @author Fernando
 */
public class AntColony {

    public static ArrayList<ArrayList<Node>> bestSolutions;
    public static PheromoneMatrix pheromoneArcs;
    public static ArrayList<Node> orders = new ArrayList<>();
    public static ArrayList<Node> nodeMap = new ArrayList<>();
    public static final float initialPheromoneValue = 1;
    public static final int numAnts = 3;

    public static void initializeArcsPheromoneLevel() {
        pheromoneArcs = PheromoneMatrix.getInstance(nodeMap, initialPheromoneValue);//usar constanteeees!
    }

    public static ArrayList<Ant> createAnts(int numAnts, Vehicle v) {
        ArrayList<Ant> list = new ArrayList<Ant>();
        for (int i = 0; i < numAnts; i++) {
            Ant newAnt = new Ant(v);
            list.add((newAnt));
        }
        return list;
    }

    public static void createNodeMap(){
        
        int tamPuntos=RouteCalculator.mapa.getPuntos().size();        
        Node node=null;
        Punto p =null;
        for (int i = 0; i <tamPuntos ; i++) {
            node = new Node();
            p = RouteCalculator.mapa.getPuntos().get(i);
            node.setX(p.getPosX());
            node.setY(p.getPosY());
            nodeMap.add(node);
        }
    }
    
    public static void createOrdersList(ArrayList<OrdenEntrega> ordenes) {
        
        int tamOrdenes=ordenes.size();
        orders = new ArrayList<>();
        Punto p;
        Node n;     
        for (int i = 0; i < tamOrdenes; i++) {
            p = ordenes.get(i).getPuntoEntrega();
            n = nodeMap.get(p.getPosX()*RouteCalculator.mapa.getAlto() + p.getPosY());
            n.setDemand(ordenes.get(i).getNumPaquetes());
            n.setInitialTimeWindow(ordenes.get(i).getPrioridad());
            n.setActualTimeWindow(ordenes.get(i).getPrioridad());
            orders.add(n);
        }
    }
    
    public static void updateNodeMapAndOrders(Ant ant){
        int cap = ant.getInitialCapacity();
        int tamRoute=ant.getRoute().size();
        int dem;
        
        for(int i=0;i < tamRoute;i++){
            dem =ant.getRoute().get(i).getDemand();
            if(cap >= dem){
                ant.getRoute().get(i).setDemand(0);
                orders.remove(ant.getRoute().get(i));
            }
            else
                ant.getRoute().get(i).setDemand(dem-cap);
        }
    }

    public static void antColonyProcedure(ArrayList<Vehicle> vehiculos, ArrayList<OrdenEntrega> ordenesEntrega) {


        createOrdersList(ordenesEntrega);
        bestSolutions = new ArrayList<>();
        int tamVehiculos=vehiculos.size();
        //initializeArcsPheromoneLevel();//se puede resetear o tener algun valor residual
        for (int n = 0; n < tamVehiculos; n++) {
            //variables para guardar la mejor solucion
            if(!vehiculos.get(n).isDisponible()){
                bestSolutions.add(new ArrayList<Node>());
                continue;
            }
            float bestCost = Float.POSITIVE_INFINITY;
            Ant bestSolution = null;

            //se crean las hormigas
            ArrayList<Ant> listaHormigas = createAnts(numAnts, vehiculos.get(n));
            int tamHormiga= listaHormigas.size();
            ArrayList<Node> tempOrders=null;
            Ant currentAnt=null;
            Punto almacenP =null;
            Node almacen = null;
            
            for (int i = 0; i < tamHormiga; i++) {
                //crear una lista temporal de las ordenes por cada hormiga
                tempOrders = (ArrayList<Node>)orders.clone();
                currentAnt = listaHormigas.get(i);
                //generar una ruta y actualizar el rastro de fermona
                while (!currentAnt.isDone()) {
                    currentAnt.selectNextDestination(tempOrders, pheromoneArcs);
                    pheromoneArcs.updatePheromoneTrail(currentAnt.getRoute());
                }
                //volver al almacen una vez que se acaba
                almacenP =RouteCalculator.almacen.getUbicacion();
                almacen = nodeMap.get(RouteCalculator.mapa.getAlto()*almacenP.getPosX()+almacenP.getPosY());
                currentAnt.getRoute().add(almacen);

                //localSearch();//hacer una optimización con un algoritmo

                //de todas las hormigas cual tuvo el mejor costo
                float currentCost = currentAnt.calculateRouteCost();
                if (currentCost < bestCost) {
                    bestCost = currentCost;
                    bestSolution = currentAnt;
                }
            }
            /*
            System.out.println("Vehiculo "+n);
            for(int k =0; k<bestSolution.getRoute().size();k++){
                System.out.println(bestSolution.getRoute().get(k).getX()+","+bestSolution.getRoute().get(k).getY());
            }*/
            updateNodeMapAndOrders(bestSolution);//"commitear" los cambios para que el siguiente vehiculo no los considere
            pheromoneArcs.updateBestPheromoneTrail(bestSolution.getRoute(), bestCost);
            bestSolutions.add(bestSolution.getRoute());
        }
    }
}
